<!-- 2021/5/15 -->
<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>五子棋</title>
    <style>
        * {
            padding: 0;
            margin: 0;
        }

        html,
        body {
            width: 100%;
            height: 100%;
            overflow: hidden;
        }

        canvas {
            margin-top: 200px;
            margin-left: 300px;
            background-color: rgb(213, 176, 146);
            display: inline-block;
            border-radius: 8px;
            border: 1px solid black;
        }

        .resultBox {
            position: absolute;
            text-align: center;
            top: 200px;
            left: 760px;
            width: 200px;
            height: 450px;
            /* background-color: #ccc; */
            background-color: rgb(213, 176, 146);
            color: 38px;
            line-height: 60px;
            font-weight: bold;
        }
    </style>
</head>

<body>
    <div class="box">
        <canvas id="canvas"></canvas>
        <div class="resultBox">
            <p class="redP">白旗已下0</p>
            <p class="blackP">黑旗已下0</p>
            <p class="resultP"></p>
        </div>
    </div>
    <script>
        //生成画布
        let canvas = document.getElementById('canvas')
        //白方p
        let redP = document.getElementsByClassName('redP')[0]
        //黑方p
        let blackP = document.getElementsByClassName('blackP')[0]
        //结果p
        let resultP = document.getElementsByClassName('resultP')[0]
        //画笔
        let ctx = canvas.getContext('2d')
        //canvas宽高
        canvas.height = canvas.width = '450'
        //颜色1  颜色2
        let color1 = '#fff'
        let color2 = 'black'
        //棋子方格大小
        let flag = 50
        //横线对象数组
        let getXLineArr = []
        //竖线对象数组
        let getYLineArr = []
        //偶数白色 基数 黑色
        let blackOrRedChessman = 0
        //所有棋子数组
        let hasChessmanArrList = []
        //坐标点数组
        //所有坐标数组
        let lineXAndlineYArr = []
        //白旗坐标数组
        let lineXAndlineYArrRed = []
        //黑棋坐标数组
        let lineXAndlineYArrBlack = []
        //初始化函数
        init()

        // 收集所有的坐标的 
        for (let i = 0; i <= canvas.width; i += flag) {
            for (let j = 0; j <= canvas.width; j += flag) {
                lineXAndlineYArr.push([i, j])
            }
        }
        //画布距离浏览器上册的距离
        let MarginTopNum = 200;
        //画布距离浏览器左册的距离
        let MarginLeftNum = 300;
        //棋子构造函数
        //x 横坐标 
        //y 纵坐标 
        //color 棋子颜色坐标 
        //x 横坐标 
        function Chessman(x, y, color) {
            this.x = x
            this.y = y
            this.color = color
        }
        Chessman.prototype.update = function () {
            ctx.save();
            ctx.beginPath()
            ctx.fillStyle = this.color// 背景颜色为白色
            ctx.arc(this.x, this.y, 20, 0, Math.PI * 2, false)
            ctx.fill()
            ctx.closePath()
        }
        canvas.addEventListener('click', function (e) {
            //当前点击的坐标  相对于canvas的坐标
            let arr = [e.clientX - MarginLeftNum, e.clientY - MarginTopNum]

            //当前点击坐标到 棋盘 0，0 的距离
            let newArrLong = Math.sqrt((0 - arr[0]) * (0 - arr[0]) + (0 - arr[1]) * (0 - arr[1]))
            let newARR = []
            //循环判断当前点击坐标到哪个棋盘坐标的距离最短，棋子放置到该坐标点
            lineXAndlineYArr.map((item, index) => {
                let newArrLongA = Math.sqrt((item[0] - arr[0]) * (item[0] - arr[0]) + (item[1] - arr[1]) * (item[1] - arr[1]))
                if (newArrLongA <= newArrLong) {
                    newARR = item; newArrLong = newArrLongA
                }
            })
            console.log("%c当前点击棋子坐标：", "color:red;font-size:20px;", newARR)
            //判断该点是否已经有棋子
            let hasYesOrNo = JSON.stringify(hasChessmanArrList).includes(JSON.stringify(newARR))
            if (!hasYesOrNo) {
                //没有的话加入棋子数组
                hasChessmanArrList.push(newARR)
            }
            else {
                alert('已经有棋子')
                return
            }
            // 判断这次点击棋子颜色
            let color = blackOrRedChessman % 2 == 0 ? color1 : color2
            //生成棋子 放置棋盘中
            new Chessman(newARR[0], newARR[1], color).update()
            //相应颜色的棋子放入对应颜色棋子数组
            blackOrRedChessman % 2 == 0 ? lineXAndlineYArrRed.push(newARR) : lineXAndlineYArrBlack.push(newARR)
            //判断棋子数量是否已经大于5
            let newlineXAndlineYArr
            blackOrRedChessman % 2 == 0 ? newlineXAndlineYArr = JSON.parse(JSON.stringify(lineXAndlineYArrRed)) : newlineXAndlineYArr = JSON.parse(JSON.stringify(lineXAndlineYArrBlack))
            //改变下一次棋子颜色使用
            blackOrRedChessman++
            //改变页面上的信息
            redP.innerHTML = '白旗已下' + lineXAndlineYArrRed.length
            blackP.innerHTML = '黑旗已下' + lineXAndlineYArrBlack.length

            //判断棋子数量是否已经大于5  没到5 决对赢不了的 ~
            if (newlineXAndlineYArr.length >= 5) {
                //向右向左倾斜判断、横向纵向判断
                leftRightFangXiang()
                //判断横向
                function xFangXiang() {
                    //横向
                    let obj = {}
                    let xArr = []
                    //深拷贝一份数组
                    let newlineXAndlineYArrx = JSON.parse(JSON.stringify(newlineXAndlineYArr))
                    // 判断属性 是否有大于等于5个的  默认数量为1 有++  无 1
                    newlineXAndlineYArrx.filter(item => {
                        if (Object.prototype.hasOwnProperty.call(obj, item[1])) {
                            obj[item[1]] += 1
                        } else {
                            obj[item[1]] = 1
                        }
                    })
                    for (let key in obj) {
                        //数量大于5时
                        if (obj[key] >= 5) {
                            //y 有五个相等 
                            for (let j = 0; j < newlineXAndlineYArrx.length; j++) {
                                //再次将 y相等的 坐标点 推向数组
                                if (newlineXAndlineYArrx[j][1] == key)
                                    xArr.push(newlineXAndlineYArrx[j][0])
                            }
                            let xArrX = xArr.sort((a, b) => a[0] - b[0])
                            let num = obj[key] - 5 + 1
                            let numm = 0
                            for (let j = 0; j < num; j++) {
                                if (numm == num) return
                                for (let i = numm; i < xArrX.length; i++) {
                                    //数组坐标点满足关系  游戏结束
                                    if (xArrX[i] + flag == xArrX[i + 1] && xArrX[i + 1] + flag == xArrX[i + 2] && xArrX[i + 2] + flag == xArrX[i + 3] && xArrX[i + 3] + flag == xArrX[i + 4]) {
                                        if (youWinFun()) {
                                            return
                                        }
                                    }
                                }
                                numm++
                            }
                        }
                    }
                }
                //判断纵向
                function yFangXiang() {
                    //纵向
                    let obj = {}
                    let xArr = []
                    let newlineXAndlineYArry = JSON.parse(JSON.stringify(newlineXAndlineYArr))
                    newlineXAndlineYArry.filter(item => {
                        if (Object.prototype.hasOwnProperty.call(obj, item[0])) {
                            obj[item[0]] += 1
                        } else {
                            obj[item[0]] = 1
                        }
                    })
                    for (let key in obj) {
                        if (obj[key] >= 5) {
                            //y 有五个相等 
                            for (let j = 0; j < newlineXAndlineYArry.length; j++) {
                                if (newlineXAndlineYArry[j][0] == key)
                                    xArr.push(newlineXAndlineYArry[j][1])
                            }
                            let xArrX = xArr.sort((a, b) => a - b)
                            let num = obj[key] - 5 + 1
                            let numm = 0
                            for (let j = 0; j < num; j++) {
                                if (numm == num) return
                                for (let i = numm; i < xArrX.length; i++) {
                                    if (xArrX[i] + flag == xArrX[i + 1] && xArrX[i + 1] + flag == xArrX[i + 2] && xArrX[i + 2] + flag == xArrX[i + 3] && xArrX[i + 3] + flag == xArrX[i + 4]) {
                                        if (youWinFun()) {
                                            return
                                        }
                                    }
                                }
                                numm++
                            }
                        }
                    }
                }
                // //向右倾斜
                function leftRightFangXiang() {
                    // 深拷贝一份数据
                    let newlineXAndlineYArrR = JSON.parse(JSON.stringify(newlineXAndlineYArr))
                    //右下方向
                    //当它是第0棵棋子的时候 其他四颗
                    // 0   [[ newARR[0]+flag, newARR[1]+50],[ newARR[0]+100, newARR[1]+100],[ newARR[0]+150, newARR[1]+150],[ newARR[0]+200, newARR[1]+200]]

                    //1    [[ newARR[0]-50, newARR[1]-50],[ newARR[0]+50, newARR[1]+50],[ newARR[0]+100, newARR[1]+100],[ newARR[0]+150, newARR[1]+150]]
                    //左下方向
                    //当它是第0棵棋子的时候 其他四颗
                    // 0   [[ newARR[0]-50, newARR[1]+50],[ newARR[0]-100, newARR[1]+100],[ newARR[0]-150, newARR[1]+150],[ newARR[0]-200, newARR[1]+200]]

                    //1    [[ newARR[0]+50, newARR[1]-50],[ newARR[0]-50, newARR[1]+50],[ newARR[0]-100, newARR[1]+100],[ newARR[0]-150, newARR[1]+150]]

                    // // x方向  注释  y方向类似
                    // 0[[newARR[0] + 50, newARR[1]], [newARR[0] + 100, newARR[1]], [newARR[0] + 150, newARR[1]], [newARR[0] + 200, newARR[1]]]

                    // 1[[newARR[0] - 50, newARR[1]], [newARR[0] + 50, newARR[1]], [newARR[0] + 100, newARR[1]], [newARR[0] + 150, newARR[1]]]

                    let newRightArrList = []
                    for (let i = 0; i < 5; i++) {
                        //x
                        if (1) {
                            newRightArrList = []
                            for (let j = 0; j < i; j++) {
                                newRightArrList.push([newARR[0] - flag * (j + 1), newARR[1]])
                            }
                            for (let k = i; k < 4; k++) {
                                newRightArrList.push([newARR[0] + flag * (k - i + 1), newARR[1]])
                            }
                            if (rightOrRight(newRightArrList, newlineXAndlineYArrR, newARR) == 'win') {
                                console.log("%c横向赢了哦~", "color:red;font-size:30px;");
                                break
                            }
                        }
                        //y
                        if (1) {
                            newRightArrList = []
                            for (let j = 0; j < i; j++) {
                                newRightArrList.push([newARR[0], newARR[1] - flag * (j + 1)])
                            }
                            for (let k = i; k < 4; k++) {
                                newRightArrList.push([newARR[0], newARR[1] + flag * (k - i + 1)])
                            }
                            if (rightOrRight(newRightArrList, newlineXAndlineYArrR, newARR) == 'win') {
                                console.log("%c纵向赢了哦~", "color:red;font-size:30px;");
                                break
                            }
                        }
                        // //左下   //  + -     张俊卿    - +
                        if (1) {
                            newRightArrList = []
                            for (let j = 0; j < i; j++) {
                                newRightArrList.push([newARR[0] + flag * (j + 1), newARR[1] - flag * (j + 1)])
                            }
                            for (let k = i; k < 4; k++) {
                                newRightArrList.push([newARR[0] - flag * (k - i + 1), newARR[1] + flag * (k - i + 1)])
                            }
                            if (rightOrRight(newRightArrList, newlineXAndlineYArrR, newARR) == 'win') {
                                console.log("%c左下赢了哦~", "color:red;font-size:30px;");
                                break
                            }
                        }
                        //右下   //  - -     张俊卿    + +
                        if (1) {
                            newRightArrList = []
                            for (let j = 0; j < i; j++) {
                                newRightArrList.push([newARR[0] - flag * (j + 1), newARR[1] - flag * (j + 1)])
                            }
                            for (let k = i; k < 4; k++) {
                                newRightArrList.push([newARR[0] + flag * (k - i + 1), newARR[1] + flag * (k - i + 1)])
                            }
                            if (rightOrRight(newRightArrList, newlineXAndlineYArrR, newARR) == 'win') {
                                console.log("%c右下赢了哦~", "color:red;font-size:30px;");
                                break
                            }
                        }
                    }
                }
            }
        })
        function rightOrRight(newRightArrList, newlineXAndlineYArrR, newARR) {
            newRightArrList = newRightArrList.map(item => JSON.stringify(item))
            newlineXAndlineYArrR = newlineXAndlineYArrR.map(item => JSON.stringify(item))
            let filterLIst = []
            newlineXAndlineYArrR.map(item => {
                newRightArrList.map(itemN => {
                    if (itemN == item) {
                        filterLIst.push(item)
                    }
                })
            })
            if (filterLIst.length == 4) {
                if (youWinFun()) {
                    return 'win'
                }
            }
        }
        //您赢了
        function youWinFun() {
            resultP.innerHTML = blackOrRedChessman % 2 == 0 ? '黑棋子方胜利' : '白棋子方胜利'
            var r = window.confirm(resultP.innerHTML + "，是否重新开始!");
            if (r == true) {
                redP.innerHTML = '白旗已下0'
                blackP.innerHTML = '黑旗已下0'
                againInit()
            }
            return 'win'
        }
        //重新开始
        function againInit() {
            // window.history.go(0)
            //横线对象数组
            getXLineArr = []
            //竖线对象数组
            getYLineArr = []
            //偶数白色 基数 黑色
            blackOrRedChessman = 0
            //所有棋子数组
            hasChessmanArrList = []
            //坐标点数组
            //白旗坐标数组
            lineXAndlineYArrRed = []
            //黑棋坐标数组
            lineXAndlineYArrBlack = []
            //初始化函数
            ctx.clearRect(0, 0, canvas.width, canvas.height)
            init()
        }
        //网格构造函数
        //color线条颜色
        //线条间隔
        function init() {
            //线条构造函数
            //线条颜色 x y
            function Line(color, x, y) {
                this.color = color;
                this.x = x
                this.y = y
            }
            //画横线
            Line.prototype.getXLine = function () {
                ctx.lineWidth = 1;
                ctx.beginPath();
                ctx.moveTo(0, this.y);
                ctx.lineTo(this.x, this.y);
                ctx.strokeStyle = this.color;
                ctx.closePath();
                ctx.fill();
                ctx.stroke();
            }
            //画竖线
            Line.prototype.getYLine = function () {
                ctx.lineWidth = 1;
                ctx.beginPath();
                ctx.moveTo(this.x, 0);
                ctx.strokeStyle = this.color;
                ctx.lineTo(this.x, this.y);
                ctx.closePath();
                ctx.fill();
                ctx.stroke();
            }
            //线条相隔大小 后面 num += flag
            let num = 0
            //线条随机颜色数组
            // let colorsList = ["#33B5E5", "#0099CC", "#AA66CC", "#9933CC", "#99CC00", "#669900", "#FFBB33", "#FF8800", "#FF4444", "#CC0000"]
            //循环画线
            for (let i = 0; i <= canvas.width; i += flag) {
                // let colorx = colorsList[Math.floor(Math.random() * 10)]
                // let colory = colorsList[Math.floor(Math.random() * 10)]
                let colorx, colory
                colorx = colory = 'black'
                getXLineArr.push(new Line(colorx, canvas.width, num))
                getYLineArr.push(new Line(colory, num, canvas.width))
                num += flag
            }
            //画横线
            getXLineArr.map(item => {
                item.getXLine()
            })
            //画竖线
            getYLineArr.map(item => {
                item.getYLine()
            })
        }
    </script>
</body>

</html>